home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr49
/
121_01.zip
/
SH.C
< prev
next >
Wrap
Text File
|
1993-06-01
|
15KB
|
714 lines
/*
HEADER: CUG 121.??;
TITLE: sh - a 'little shell' command interpreter;
VERSION: 2.2;
DATE: 01/06/86;
DESCRIPTION: "The little shell is designed to provide a `Unix-like'
shell for CP/M, replacing the CP/M CCP as the primary user
interface. It provides two convenient mechanisms for
chaining commands together: they may be typed on a single
line, separated by commas; or files of commands called Shell
scripts may be executed.
The CP/M operating environment does not lend itself to the
use of frequently invoked commands in the form of executable
files. Consequently, the shell has an extensive array of
built-in commands, including: cat, ccp, cd, clr, echo, exit,
lock, logout, ls, pwd, ren, rm, sleep, unlock.
The above is accomplished at a cost: the shell is written in
BDS C and is five times the size of the CP/M CCP; hence it
takes somewhat longer to load into memory at warm boots.
Also, since the shell clobbers the CCP, submit does not work
when the shell is invoked.";
KEYWORDS: shell, command, interpreter;
SYSTEM: CP/M;
FILENAME: SH.C;
WARNINGS: "Copyright (c) 1982 Steve Blasingame.
Requires doglob.h and fcb.h for compile.";
AUTHORS: Steve Blasingame;
COMPILERS: BDS-C 1.50;
*/
#include <bdscio.h>
#include <hardware.h>
#include "fcb.h"
#include "doglob.h"
#define EOT 4 /* ascii eot */
#define PROMPT "$ " /* prompt string */
#define TABSIZE 7 /* spaces in a tab */
#define CNTLH 8 /* backspace */
#define DEL 0x7f /* ascii del */
#define QUIT 0x1c /* cntl-backslash */
#define LINEKILL 24 /* cntl-x */
#define SLEEPNO 16 /* sleep constant for 4 Mz Z80a */
#define COMMENT '#' /* comment line */
#define stdin 0 /* for console io */
#define stdout 1 /* for console io */
#define FILE struct _buf
#define SHBUF 0xf54b /* Buffer in current bios */
char combuf[MAXLINE]; /* command line buffer */
char globs[GLOBMAX*FILENAMESIZE]; /* expansion buffer */
int argvp[20]; /* array of argument pointers */
int argcp; /* argument count for execv */
int testmode; /* verbose flag */
int flag; /* for lst function */
/* Structure of Shell's Storage Area in the CBIOS */
struct exbuf {
char _shdsk; /* current directory */
int _shsav; /* buffer save flag */
char _nocli; /* no shell option */
char _shbuf[BUFSIZ]; /* buffer */
};
struct exbuf *iop; /* pointer to bios buffer */
int parse(); /* parse command line */
int dolocal(); /* do built-in shell commands */
int lexecv(); /* local execv until C1.45a */
char *b_gets(); /* local crt driver */
char pwd(); /* return current logical disk */
char chdir(); /* select disk */
int filprt(); /* list selected file on screen */
int lst(); /* format directory listing */
int dofile(); /* process shell script */
int flock(); /* lock or unlock file */
int doshell(); /* exec the shell */
int expand(); /* expand global filenames */
int dozap(); /* interactively delete files */
int doglob(); /* parse global file expressions */
int more(); /* list multiple files on screen */
int crfil(); /* fill memory */
int strcmp();
main(argc,argv)
int argc;
char *argv[];
{
char *cp;
_allocp = 0; /* initializer */
iop = SHBUF; /* initializer */
testmode = 0; /* initializer */
iop->_nocli = 0; /* default shell on reboot */
if (argc == 2 && (strcmp(argv[1],"-T") == 0)) testmode =1;
if (argc == 3 && (strcmp(argv[1],"-F") == 0)) parse(strlower(argv[2]));
bdos(0x0e, iop->_shdsk); /* restore cwd */
while (1) {
crfil(combuf,MAXLINE,0);
if (!iop->_shsav) {
puts(PROMPT);
if (!b_gets(combuf))
break;
else {
cp = combuf;
if (parse(cp) == -1)
puts("what?\n");
}
}
else {
strcpy(combuf,&iop->_shbuf);
iop->_shsav = 0;
cp = combuf;
if (parse(cp) == -1)
puts("syntax error\n");
}
}
chdir('a'); /* home directory */
if (execl("a:login",0) == -1) /* admittedly a kluge */
;
doshell();
}
parse(cp)
char *cp;
{
int i;
char *pointer;
i=0;
argvp[i]=cp;
if (testmode) puts(cp);
if (*cp == '\n')
return 0;
else {
while(*cp == ' ') /* skip blanks */
cp++;
argvp[i]=cp;
while(*++cp != NULL) {
if (*cp == ' ') {
i++;
*cp = NULL;
argvp[i]=cp+1;
}
else if (*cp == ';') {
if (cp == combuf || *(cp+1) != ' ')
return -1;
else {
i++;
*cp = NULL;
argvp[i]=NULL;
cp += 2;
strcpy(iop->_shbuf,cp);
iop->_shsav = 1;
break;
}
}
else if (*cp == '\n') {
i++;
*cp = NULL;
argvp[i]=NULL;
break;
}
}
argcp = 0;
while(1) {
if (!argvp[argcp]) break;
argcp++;
}
if (dolocal(&argvp)) {
return 0;
}
else {
pointer = &argvp + 1;
if (lexecv(argvp[0], pointer) == -1) {
if (dofile(argcp,&argvp) == -1) {
puts(argvp[0]);
puts(": not found\n");
}
return 0;
}
}
}
return(-1);
}
dolocal(ptr)
char *ptr[];
{
int value;
char *tpoint;
if (strcmp(*ptr,"clr") == 0) {
puts(CLEARS);
return 1;
}
else if (strcmp(*ptr,"ccp") == 0) {
iop->_nocli = 1; /* set no shell mode */
bios(1,0); /* warm boot cpm */
}
else if (strcmp(*ptr,"exit") == 0) {
iop->_shsav = 0; /* flush shell buffer */
bios(1,0); /* warm boot cpm */
}
else if (**ptr == COMMENT) return 1;
else if (strcmp(*ptr,"logout") == 0) {
chdir('a'); /* set default directory */
execl("a:login",0);
;
return 1;
}
else if (strcmp(*ptr,"echo") == 0) {
++ptr;
while (*ptr != 0) {
puts(*ptr);
putchar(' ');
ptr++;
}
putchar('\n');
return 1;
}
else if (strcmp(*ptr,"pwd") == 0) {
putchar(pwd()); /* print current disk */
puts(":\n");
return 1;
}
else if (strcmp(*ptr,"cd") == 0) {
chdir(**++ptr); /* set default disk */
return 1;
}
else if (strcmp(*ptr,"sleep") == 0) {
value = (SLEEPNO * atoi(*++ptr));
sleep(value);
return 1;
}
else if (strcmp(*ptr,"rm") == 0) {
++ptr; /* remove files */
if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
puts("usage: rm [file] [file...]\n");
return 1;
}
while (*ptr != NULL && **ptr != NULL) {
expand(dozap,*ptr,0);
ptr++;
}
return 1;
}
else if (strcmp(*ptr,"lock") == 0) {
++ptr;
if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
puts("usage: lock [file] [file...]\n");
return 1;
}
while (*ptr != NULL && **ptr != NULL) {
expand(flock,*ptr,1);
ptr++;
}
return 1;
}
else if (strcmp(*ptr,"unlock") == 0) {
++ptr;
if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
puts("usage: unlock [file] [file...]\n");
return 1;
}
while (*ptr != NULL && **ptr != NULL) {
expand(flock,*ptr,0);
ptr++;
}
return 1;
}
else if (strcmp(*ptr,"mv") == 0) {
tpoint = *++ptr;
++ptr;
value = *ptr;
if (tpoint == 0 || *tpoint == '\n' || **ptr == '\n' || *ptr == 0) {
puts("usage: mv [source] [dest]\n");
return 1;
}
if (index(tpoint,"*") != -1 || index(tpoint,"?") != -1) {
puts(tpoint);
puts(": ambiguous\n");
return 1;
}
else if (index(value,"*") != -1 || index(value,"?") != -1) {
puts(value);
puts(": ambiguous\n");
return 1;
}
else if (fstat(*ptr) == -1) {
if ((value=fstat(tpoint)) == 1) {
puts(tpoint);
puts(": readonly\n");
return 1;
}
else if (value == 0) {
if (rename(tpoint,*ptr) == -1) {
puts(*ptr);
puts(": file not found\n");
return 1;
}
}
else if (value == -1) {
puts(tpoint);
puts(": file not found\n");
return 1;
}
}
else {
puts(*ptr);
puts(": file already exists\n");
return 1;
}
return 1;
}
else if (strcmp(*ptr,"ls") == 0) {
++ptr;
flag = 0; /* a kluge */
if (!(*ptr == 0 || **ptr == '\n' || **ptr == 0)) {
while (*ptr != NULL && **ptr != NULL) {
expand(lst,*ptr,0);
ptr++;
}
putchar('\n');
}
else {
expand(lst,"*.*",0);
putchar('\n');
}
return 1;
}
else if (strcmp(*ptr,"cat") == 0) {
++ptr;
if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
puts("usage: cat [file] [file...]\n");
return 1;
}
while (*ptr != 0) {
expand(filprt,*ptr,0);
ptr++;
}
return 1;
}
else return 0;
}
lexecv(pgm,argv)
char *pgm;
char **argv;
{
int p[10]; /* only 10 for now */
int argcp, val;
argcp=10;
val=0;
while (*argv != NULL) {
p[11-argcp] = *argv++;
if (--argcp < 0) {
argcp = 0;
break;
}
}
p[11-argcp] = NULL;
/* replace this grossness with something reasonable */
val=execl(pgm,p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10]);
return val;
}
dofile(largc,largv)
int largc;
char *largv[];
{
char local[BUFSIZ], tmpbuf[BUFSIZ], *bp, scratch[BUFSIZ];
int x;
FILE file;
scratch[0]=0; /* initializer */
strcpy(local,largv[0]);
strcat(local,".sh");
if (fopen(local,file) == -1) return -1;
while (fgets(local,file)) {
bp = local;
while (1) {
if (*bp) {
if (*bp == '$') {
*bp = NULL;
strcpy(tmpbuf,local);
if ((x=atoi(++bp)) <= largc) {
strcat(tmpbuf,largv[x]);
}
else {
puts("invalid argument\n");
return 0;
}
strcat(tmpbuf,++bp);
strcpy(local,tmpbuf);
bp -= 2; /* klugy */
}
else if (*bp == '\n') {
*bp = NULL;
}
bp++;
}
else break;
}
strcat(scratch,local);
strcat(scratch," ; ");
if (iop->_shsav) {
if ((strlen(iop->_shbuf)+strlen(scratch)) >= BUFSIZ) {
puts("sh: buffer overflow\n");
return 0;
}
}
}
if (iop->_shsav) {
strcat(scratch,iop->_shbuf);
strcpy(iop->_shbuf,scratch);
}
else {
*(scratch+strlen(scratch)-1) = NULL; /* kluge */
*(scratch+strlen(scratch)-2) = '\n'; /* more */
strcpy(iop->_shbuf,scratch);
iop->_shsav=1;
}
return 0;
}
char *
b_gets(buf)
char *buf;
{
char c;
int tab;
tab = TABSIZE;
while((c=bios(3,0)) != '\r') {
if (c == QUIT) {
puts("\nQuit\n");
bios(1,0); /* warm boot cpm */
}
if ((c == CNTLH || c == DEL) && buf !=combuf) {
putchar(CNTLH);
putchar(' ');
putchar(CNTLH);
buf -= 2;
}
else if (c == '\t') {
putchar(' ');
while (--tab) {
*buf = ' ';
buf++;
putchar(' ');
}
tab = TABSIZE;
}
else if (c == LINEKILL) {
while (1) {
putchar(CNTLH);
putchar(' ');
putchar(CNTLH);
if (buf == (combuf-1))
break;
else
--buf;
}
puts(PROMPT);
}
else if (c == EOT) {
puts("logout\n");
return 0;
}
else {
*buf = c;
putchar(c);
}
if (buf != (combuf+MAXLINE))
buf++;
}
putchar('\n');
*buf = '\n';
*++buf = '\0';
return combuf;
}
pwd() /* return current directory */
{
return(iop->_shdsk+97);
}
chdir(c) /* cp/m function 14 */
char c;
{
if (c < 65 || c > 122)
return 0;
c -= 97;
bdos(0x0e,c);
iop->_shdsk = c;
return c;
}
flock(filnam,mode) char *filnam; int mode; {
fcb address;
char *offset;
offset = &address.f_name[8];
setfcb(address,filnam);
if (mode == TRUE) *offset |= '\200';
else *offset &= 0x7f;
if (bdos(30,&address) == 0xff) {
puts(filnam);
puts(": not found.\n");
}
return(0);
}
filprt(filnam)
char *filnam;
{
FILE fbuf;
char c, str[BUFSIZ];
int count;
count = 0;
if (fopen(filnam,fbuf) == -1)
return -1;
else {
puts(CLEARS);
putchar('-'); puts(filnam); puts("-\n");
for (;;) {
if (!fgets(str,fbuf)) {
fclose(fbuf);
fflush(fbuf);
puts("-eof-");
if (bios(3,0) == 'q') {
puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
return -1;
}
putchar('\n');
return 0;
}
if ((count += 1) == 22) {
count = 0;
puts("-more-");
if ((c=bios(3,0)) == 'n') {
puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
fclose(fbuf);
return 1;
}
else if (c == 'q') {
fclose(fbuf);
puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
return -1;
}
puts(CLEARS);
putchar('-'); puts(filnam); puts("-\n");
}
fputs(str,stdout);
}
}
puts("-eof-");
if (bios(3,0) == 'q') {
puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
return -1;
}
else putchar('\n');
return 0;
}
lst(vector)
char *vector;
{
int q; /* flag must be an external */
if (flag == 3) {
puts(vector);
putchar('\n');
flag = 0;
}
else {
puts(vector);
for (q = 0; q != (20-strlen(vector)); q++)
putchar(' ');
flag++;
}
return 0;
}
pickout(fcon,name) fcb *fcon; char *name; {
char i;
if (fcon->f_entry) {
*name++ = " abcd"[fcon->f_entry & 0x7f] ;
*name++ = ':' ;
}
for (i=0; fcon->f_name[i] != ' ' && i < 8; i++)
*name++ = tolower(fcon->f_name[i]) ;
*name++ = '.';
for (i=8; fcon->f_name[i] != ' ' && i < 11; i++)
*name++ = tolower(fcon->f_name[i]) ;
*name = 0;
}
remove(filnam) char *filnam; {
fcb address;
if (fstat(filnam) == 1) return 1; /* readonly file */
setfcb(address,filnam);
if (bdos(19,&address) == 0xff) /* cpm delete call */
return -1; /* file not found */
else return 0;
}
doshell()
{
execl("a:sh",0);
}
fstat(filnam) char *filnam; {
char *byte, c;
fcb address;
setfcb(address,filnam);
if ((c=bdos(17,&address)) == 255)
return -1; /* file not found */
byte =(0x80 + (c * 32) + _MBYTE); /* permission byte */
if ((*byte & '\200') == 0) return 0; /* readwrite */
else return 1; /* readonly */
}
expand(func,parm1,parm2) /* perform global file expansions */
int (*func)();
char *parm1;
int parm2;
{
int count, ret;
count = GLOBMAX;
crfil(globs,count*FILENAMESIZE,0xff);
while (count--)
globv[count] = &globs[count*FILENAMESIZE];
globv[GLOBMAX]=0;
if ((ret = doglob(parm1)) >= 1) {
qsort(globs,ret,FILENAMESIZE,strcmp);
count = 0;
while (count < ret) {
if ((*func)(globv[count],parm2) == -1)
break;
count++;
}
}
else {
puts(parm1);
puts(": no match\n");
}
return 0;
}
dozap(file) char *file; {
int ret;
if ((ret = remove(file)) == -1) {
puts(file);
puts(": not found\n");
}
else if (ret == 1) {
puts(file);
puts(" readonly -- zap?");
if (bios(3,0) == 'y') {
flock(file,0);
remove(file);
}
putchar('\n');
}
return 0;
}
doglob(string) /* glob - expand filename expressions */
char *string;
{
char f, c, buf[20];
fcb address;
fcb *dirbuf;
int flag, q, i;
flag=0;
i=0;
if (strlen(string) == 2 && *(string+1) == ':') {
setfcb(address,"????????.???");
address.f_entry = tolower(*string)-96;
}
else
setfcb(address,string);
for (f=17; (c=bdos(f,&address)) != 255; f=18) {
dirbuf = (0x80 + (c * 32));
dirbuf->f_entry = address.f_entry;
pickout(dirbuf, buf);
strcpy(globv[i],buf);
if (++i == GLOBMAX) break;
}
globv[i] = 0; /* null terminate vector */
return i;
}
index(string,ch) /* return pointer to ch in string */
char *string, *ch;
{
while (*string) {
if (*string==*ch)
return string;
string++;
}
return -1;
}
crfil(address,length,byte) /* zero fill at address for length bytes */
char *address, byte;
unsigned length;
{
while (--length) {
*++address = byte;
}
return 0;
}